package com.example.socket.filter.session;

import com.example.socket.core.Session;
import com.example.socket.core.SessionContext;
import com.example.socket.utils.ByteUtils;
import com.example.socket.utils.RandomUtils;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.SocketAddress;
import java.util.Collection;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 序列号生成器，用于生成SESSION ID
 * @author Ramon
 */
public class NettySessionFactory implements SessionFactory<Channel> {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private static final int INIT_SIZE = 4096;

    private AtomicLong sequence = new AtomicLong(0x00FFFF00L);

    /** SESSION 列表 */
    private ConcurrentMap<Long, Session> sessions = new ConcurrentHashMap<>(INIT_SIZE);

    // ------

    @Override
    public Session createSession(Channel channel, SessionUtil creator) {
        long id = nextId();
        if (sessions.containsKey(id)) {
            logger.warn("SESSION ID [{}] 已被使用 , 重新生成...", id);
            id = nextId();
        }
        Session session = creator.createSession(id, channel);
        Session absent = sessions.putIfAbsent(id, session);
        while (absent != null && absent != session) {
            logger.warn("SESSION ID [{}] 已被使用 , 重新生成...", id);
            id = nextId();
            session = creator.createSession(id, channel);
            absent = sessions.putIfAbsent(id, session);
        }
        SessionContext context = new SessionContext(UUID.randomUUID().toString());
        session.bindContext(context);
        logger.debug("SESSION[{}]绑定上下文对象[{}], 连接[{}]", id, context.getSessionId(), session.getRemoteAddress());
        return session;
    }

    @Override
    public Session getSession(long id) {
        return sessions.get(id);
    }

    @Override
    public Collection<Session> getAll() {
        return sessions.values();
    }

    @Override
    public void destorySession(Session session) {
        SocketAddress address = session.getRemoteAddress();
        long sid = session.getId();
        // 关闭连接
        // session.destroy();
        // 销毁SESSION
        session.destory();
        // 移除SESSION
        sessions.remove(sid, session);
        logger.debug("SESSION[{}]销毁, 连接[{}]", new Object[]{sid, address});
    }

    // ---------

    /**
     * 获取下一个序列号
     * @return
     */
    private long nextId() {
        long prefix = (System.currentTimeMillis() / 1000) % 0xFFFFFFFFL;
        long random = RandomUtils.nextInt(0x0F);
        long sn = sequence.getAndIncrement() % 0x00FFFFFFL;
        long result = (prefix << 32) | (sn << 8) | (random << 4);
        byte[] b1 = ByteUtils.longToByte(result);
        long suffix = 0;
        for (byte b : b1) {
            suffix += (b & 0xFF);
        }
        suffix = suffix % 0x0FL;
        result |= suffix;
        return result;
    }

    @Override
    public void addSession(Session session) {
        sessions.put(session.getId(), session);
    }

}
